	/**
	 * author: fangqk
	 * PC端图片上传低耦合闭包js，适合有一定js基础的你
	 * 注意：需要依赖jQuery
	 * new Promise(resolve, reject)处理异步方法结果回调，配合catch一次抓取任何异常，避免回调地狱
	 * 其他异步回调如process上传进度的回调写在方法参数表中即可对外暴露
	 */
	var FileUpload = function(initData) {
		/**
		 * fileId：input:file的id
		 * uploadUrl：后台接受图片的URL地址
		 * maxSize：图片的最大大小，大于此值即进行压缩
		 * minSize：图片的最小大小，小于这个值不能上传，认为不够清晰，按需设置
		 * reqMaxSize：服务器最大接收数据大小，用于限制png和gif格式的图片上传
		 */
		var data = {
			fileId: 'fileInput',
			uploadUrl: '/img/uploadImg',
			maxSize: 1.0*1024*1024,
			minSize: 100*1024,
			reqMaxSize: 4*1024*1024,
			allowType: ['jpg','png','gif','jpeg']
		}
		
		var init = function() {
			// 如果initData有传值，则以initData的参数值为准，否则使用data中的默认值
	        $.extend(data, initData);
	    }
		
		init();
		
		/**
		 * 对外暴露的方法要以this.methodName = function(){} 声明，其他不能暴露的方法则用普通方法声明
		 * 上传成功回调方法callback，失败或异常回调方法errBack
		 * @param fileId
		 * @returns
		 */
		this.fileChange = function(callback, process, errBack) {
			var file = document.getElementById(data.fileId);
			var fileInfo = file.files[0];
			if(fileInfo==null){
				return errBack("您未选择任何图片！");
			}
			
			var fileName = fileInfo.name.toLowerCase();
			//获取文件后缀名
			var typeName = fileName.substring(fileName.lastIndexOf('.') + 1);
			if(!validateType(typeName, data.allowType)){
				return errBack("不支持您上传的"+ typeName +"格式文件");
			}

			var size = fileInfo.size;
			var imageprop = 100;
			if((typeName == 'gif' || typeName == 'png') && size > data.reqMaxSize){
				return errBack("您上传的"+ typeName +"格式图片不能大于"+ data.reqMaxSize/(1024*1024) +"mb");
			}else if(size < data.minSize){
				return errBack("您上传的"+ fileName +"图片不能小于"+ data.minSize/1024 +"Kb");
			}else if(size > data.maxSize){
				imageprop = data.maxSize*100/size;
			}
			
			readFile(fileInfo).then(function(imgBase64) {
				return pressImage(imgBase64, imageprop/100, typeName, process);
			}).then(function(ret) {
				return convertBase64UrlToBlob(ret.pressedData, fileName, ret.proportion);
			}).then(function(form) {
				return uploadFile(form, process);
			}).then(function(retData) {
				callback(retData);
			}).catch(function(errMsg){
				if(errMsg){
					return errBack(errMsg);
				}
			})
		}
		
		/**
		 * 判断图片是否为支持的类型
		 * @param typeName
		 * @param allowType
		 * @returns
		 */
		function validateType(typeName,allowType) {
			for(var i=0;i<allowType.length;i++){
				if(typeName==allowType[i]){
					return true;
				}
			}
			return false;
		}
		
		/**
		 * 读取Base64
		 * @param file
		 * @param callback
		 * @param err
		 * @returns
		 */
		function readFile(file) {
			return new Promise(function(callback, err) {
				//js通过id获取上传的文件对象
				if (window.FileReader) {
					var reader = new FileReader();
					//监听文件读取结束后事件
					reader.onloadend = function (e) {
						// 图片base64
						callback(e.target.result);
					}
					reader.readAsDataURL(file);
				}else{
					return err("您的设备不支持文件读取");
				}
			})
		}
	
		/**
		 * 按比例压缩图片
		 * @param imgBase64
		 * @param rate
		 * @param callBack
		 * @param err
		 * @returns
		 */
		function pressImage(imgBase64, rate, typeName, process) {
			return new Promise(function(callBack, err) {
				// 压缩图片，png和gif格式的图片保留大量细节，可能是用户必须保留的，不做压缩
				var img = new Image();
				img.src = imgBase64;
				img.onload = function() {
					var width = img.width;
					var height = img.height;
					if(width < height){
						return err("图片比例不正常！");
					}
					// 求照片的宽和高的比例保留小数点后两位小数
					var proportion = (width/height).toFixed(2);
					if(rate!=1 && rate!='1' && typeName != 'gif' && typeName != 'png'){
						process(" 压缩图片......")
							img.width = width * rate;
							img.height = height * rate;
							//生成canvas
							var canvas = document.createElement("canvas");
							var ctx = canvas.getContext("2d");
							canvas.width = img.width;
							canvas.height = img.height;
							ctx.drawImage(img, 0, 0, img.width, img.height);
							var ret = {pressedData: canvas.toDataURL('image/jpeg', 0.9), proportion: proportion}
							callBack(ret);
			        }else{
			        	var ret = {pressedData: imgBase64, proportion: proportion}
			        	callBack(ret);
			        }
				}
			})
		}
		
		/**
		 * 将Base64Url转换为Blob
		 * @param imgBase64
		 * @param fileName
		 * @param callback
		 * @param err
		 * @returns
		 */
		function convertBase64UrlToBlob(imgBase64, fileName, proportion){
			return new Promise(function(callback, err) {
				var bytes=window.atob(imgBase64.split(',')[1]);//去掉url的头，并转换为byte
				//处理异常,将ascii码小于0的转换为大于0
				var ab = new ArrayBuffer(bytes.length);
				var ia = new Uint8Array(ab);
				for(var i = 0; i < bytes.length; i++) {
					ia[i] = bytes.charCodeAt(i);
				}
				var blobImg;
				//获取文件后缀名
				var imgTypeName = fileName.substring(fileName.lastIndexOf('.') + 1);
				if(imgTypeName=="png"){
					blobImg = new Blob( [ab] , {type : 'image/png'});
				}else if(imgTypeName=="jpg"){
					blobImg = new Blob( [ab] , {type : 'image/jpg'});
				}else if(imgTypeName=="jpeg"){
					blobImg = new Blob( [ab] , {type : 'image/jpeg'});
				}else if(imgTypeName=="gif"){
					blobImg = new Blob( [ab] , {type : 'image/gif'});
				}else{
					return err("仅支持jpg、png、jpeg、gif格式的图片！");
				}
				var form = new FormData();
				form.append("fileField", blobImg, fileName);
				form.append("proportion", proportion);
				callback(form);
			})
		}
		
		/**
		 * 
		 * @param form
		 * @returns
		 */
		function uploadFile(form, process) {
			return new Promise(function(callback, err) {
				$.ajax({
					url: data.uploadUrl,
					type: "post",
					data: form,
					processData: false,
					contentType: false,
					dataType: "json",
					error: function() {
						return err("服务器错误，请稍后再试...");
					},
					success: function(retData){
						callback(retData);
					},
					xhr:function(){ //在jquery函数中直接使用ajax的XMLHttpRequest对象
						var xhr = new XMLHttpRequest();
						xhr.upload.addEventListener("progress", function(evt){
							if (evt.lengthComputable) {
								var percentComplete = Math.round(evt.loaded * 100 / evt.total);
								process(percentComplete.toString()+"%");
							}
						}, false);
						return xhr;
					}
				});
			})
		}
	}